package com.tsd.jxc.order.service.impl;

import com.tsd.core.constants.Constants;
import com.tsd.core.thread.ThreadPoolTaskUtil;
import com.tsd.core.utils.DoubleUtil;
import com.tsd.core.utils.HlpUtils;
import com.tsd.core.utils.ListUtil;
import com.tsd.core.vo.HlpException;
import com.tsd.core.vo.PageBean;
import com.tsd.jxc.buy.dao.JxcBuyOrderDetailMapper;
import com.tsd.jxc.buy.dao.JxcBuyOrderMapper;
import com.tsd.jxc.buy.entity.JxcBuyOrderDetailExt;
import com.tsd.jxc.buy.entity.JxcBuyOrderExt;
import com.tsd.jxc.fin.FinanceConstants;
import com.tsd.jxc.fin.entity.JxcFinanceAccountDetailExt;
import com.tsd.jxc.fin.service.JxcFinanceAccountDetailService;
import com.tsd.jxc.order.dao.JxcOrderAmountDetailMapper;
import com.tsd.jxc.order.entity.JxcOrderAmountDetail;
import com.tsd.jxc.order.entity.JxcOrderAmountDetailExt;
import com.tsd.jxc.order.service.JxcOrderAmountDetailService;
import com.tsd.jxc.sale.dao.JxcSaleOrderDetailMapper;
import com.tsd.jxc.sale.dao.JxcSaleOrderMapper;
import com.tsd.jxc.sale.entity.JxcSaleOrderExt;
import com.tsd.jxc.stock.StockConstants;
import com.tsd.service.BaseServiceImpl;
import com.tsd.system.entity.SysUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

import static com.tsd.core.constants.Constants.VALUE_NO;

/**
 * 描述：JxcOrderAmountDetail 服务实现层
 *
 * @author Hillpool
 * @date 2022/11/04 18:01:29
 */
@Service
public class JxcOrderAmountDetailServiceImpl extends BaseServiceImpl implements JxcOrderAmountDetailService {

    @Resource
    private JxcOrderAmountDetailMapper jxcOrderAmountDetailMapper;
    @Resource
    private JxcBuyOrderMapper jxcBuyOrderMapper;
    @Resource
    private JxcBuyOrderDetailMapper jxcBuyOrderDetailMapper;
    @Resource
    private JxcSaleOrderMapper jxcSaleOrderMapper;
    @Resource
    private JxcSaleOrderDetailMapper jxcSaleOrderDetailMapper;
    @Resource
    private JxcFinanceAccountDetailService jxcFinanceAccountDetailService;

    @Override
    public JxcOrderAmountDetail getJxcOrderAmountDetailById(Long id) throws Exception {
        return jxcOrderAmountDetailMapper.selectByPrimaryKey(id);
    }

    @Override
    public JxcOrderAmountDetailExt queryBySid(String sid) throws Exception {
        return jxcOrderAmountDetailMapper.selectBySid(sid);
    }

    @Override
    public void deleteJxcOrderAmountDetails(List<String> list, SysUser opUser) throws Exception {
        for (String sid : list) {
            JxcOrderAmountDetail old = jxcOrderAmountDetailMapper.selectBySid(sid);
            super.checkEmpty(old, "该记录不存在");
            super.autoInjectBaseData(old, opUser, TYPE_DELETE);
            jxcOrderAmountDetailMapper.updateByPrimaryKeySelective(old);
        }
    }

    @Override
    public void deleteJxcOrderAmountDetailsByOrderSid(List<String> list, SysUser opUser) throws Exception {
        if (list.isEmpty()) {
            return;
        }
        Map<String, Object> params = new HashMap<>();
        params.put("dr", 1);
        params.put("dr_date", new Date());
        params.put("dr_user_name", opUser.getName());
        params.put("dr_user_sid", opUser.getSid());
        params.put("list", list);
        jxcOrderAmountDetailMapper.update2DeleteByOrderSidList(params);
    }

    @Override
    public void cancelJxcOrderAmountDetailsByOrderSid(List<String> list, SysUser opUser) throws Exception {
        Map<String, Object> params = new HashMap<>();
        params.put("state", VALUE_NO);
        params.put("update_date", new Date());
        params.put("updator_sid", opUser.getName());
        params.put("updator_name", opUser.getSid());
        params.put("list", list);
        jxcOrderAmountDetailMapper.update2CancelByOrderSidList(params);
    }

    @Override
    public void saveJxcOrderAmountDetail(JxcOrderAmountDetailExt record, SysUser opUser) throws Exception {
        super.checkEmpty(record.getType(), "缺少参数：type");
        super.checkEmpty(record.getOrder_sid(), "缺少参数：order_sid");
        super.checkEmpty(record.getPay_type(), "请填写支付方式");
        if (HlpUtils.isEmpty(record.getId())) {
            super.autoInjectBaseData(record, opUser, this.TYPE_CREATE, new Date(), record.getThe_date());
            jxcOrderAmountDetailMapper.insertSelective(record);
            if (!HlpUtils.isEmpty(record.getType()) && StockConstants.PAY_TYPE_FOR_BUY.equals(record.getType())) {
                // 采购付款生成对应的对账单
                JxcBuyOrderExt orderExt = jxcBuyOrderMapper.selectBySid(record.getOrder_sid());
                super.checkEmpty(orderExt, "采购订单不存在");
                JxcFinanceAccountDetailExt accountDetailExt = genBuyPayFinanceAccountDetailObj(orderExt, record, record.getAmount());
                if (HlpUtils.isEmpty(accountDetailExt.getRelated_party_sid())) {
                    //如果供应商的sid不存在，则获取详情中的第一个供应商sid
                    List<JxcBuyOrderDetailExt> detailExts = jxcBuyOrderDetailMapper.selectByOrderSid(record.getOrder_sid());
                    if (detailExts != null && !detailExts.isEmpty()) {
                        accountDetailExt.setRelated_party_sid(detailExts.get(0).getSupplier_sid());
                    }
                }
                jxcFinanceAccountDetailService.saveJxcFinanceAccountDetail(accountDetailExt, opUser);
            }
            if (!HlpUtils.isEmpty(record.getType()) && StockConstants.PAY_TYPE_FOR_SALE.equals(record.getType())) {
                // 销售收款生成对应的对账单
                JxcSaleOrderExt saleOrderExt = jxcSaleOrderMapper.selectBySid(record.getOrder_sid());
                super.checkEmpty(saleOrderExt, "销售订单不存在");
                JxcFinanceAccountDetailExt accountDetailExt = genSalePayFinanceAccountDetailObj(saleOrderExt, record, record.getAmount());
                jxcFinanceAccountDetailService.saveJxcFinanceAccountDetail(accountDetailExt, opUser);
            }
        } else {
            super.autoInjectBaseData(record, opUser, this.TYPE_UPDATE);
            super.updateYyyyMmdd(record, record.getThe_date());
            jxcOrderAmountDetailMapper.updateByPrimaryKeySelective(record);
        }
        this.updateOrderReceivedOrPaid(record, opUser);
    }

    /**
     * 构建采购付款对账对象
     */
    private JxcFinanceAccountDetailExt genBuyPayFinanceAccountDetailObj(JxcBuyOrderExt orderExt, JxcOrderAmountDetailExt record, BigDecimal amount) {
        if (orderExt == null) {
            return null;
        }
        // 生成对账
        JxcFinanceAccountDetailExt accountDetailExt = new JxcFinanceAccountDetailExt();
        accountDetailExt.setRelated_party_sid(orderExt.getSupplier_sid());
        accountDetailExt.setType(FinanceConstants.TYPE_CASH_OUT);
        accountDetailExt.setCode(orderExt.getCode());
        accountDetailExt.setFund_account_sid(record.getFund_account_sid());
        accountDetailExt.setCash_in_amount(amount);
        accountDetailExt.setRelation_sid(orderExt.getSid());
        accountDetailExt.setRelation_code(orderExt.getCode());
        accountDetailExt.setThe_date(new Date());
        accountDetailExt.setBill_type(FinanceConstants.BILL_TYPE_BUY_PAY);
        return accountDetailExt;
    }

    /**
     * 构建销售收款对账实体
     */
    private JxcFinanceAccountDetailExt genSalePayFinanceAccountDetailObj(JxcSaleOrderExt saleOrderExt, JxcOrderAmountDetailExt record, BigDecimal amount) {
        if (saleOrderExt == null) {
            return null;
        }
        // 生成对账
        JxcFinanceAccountDetailExt accountDetailExt = new JxcFinanceAccountDetailExt();
        accountDetailExt.setRelated_party_sid(saleOrderExt.getClient_sid());
        accountDetailExt.setType(FinanceConstants.TYPE_CASH_IN);
        accountDetailExt.setCode(saleOrderExt.getCode());
        accountDetailExt.setFund_account_sid(record.getFund_account_sid());
        accountDetailExt.setCash_in_amount(amount);
        accountDetailExt.setRelation_sid(saleOrderExt.getSid());
        accountDetailExt.setRelation_code(saleOrderExt.getCode());
        accountDetailExt.setThe_date(new Date());
        accountDetailExt.setBill_type(FinanceConstants.BILL_TYPE_SALE_PAY);
        return accountDetailExt;
    }

    private void updateOrderReceivedOrPaid(JxcOrderAmountDetailExt detailExt, SysUser opUser) throws Exception {
        double totalAmount = jxcOrderAmountDetailMapper.sumValidByOrderSid(detailExt.getOrder_sid());
        if (StockConstants.PAY_TYPE_FOR_BUY.equals(detailExt.getType())) {
            JxcBuyOrderExt orderExt = jxcBuyOrderMapper.selectBySid(detailExt.getOrder_sid());
            super.checkEmpty(orderExt, "采购单不存在");
            double unPayAmount = DoubleUtil.sub(orderExt.getShould_pay_amount(), totalAmount);
            if (unPayAmount < 0) {
                throw new HlpException("已付金额不能大于应付金额");
            }
            orderExt.setPaid_amount(BigDecimal.valueOf(totalAmount));
            orderExt.setUn_pay_amount(BigDecimal.valueOf(unPayAmount));
            super.autoInjectBaseData(orderExt, opUser, this.TYPE_UPDATE);
            jxcBuyOrderMapper.updateByPrimaryKeySelective(orderExt);
            detailExt.setRemain_amount(orderExt.getUn_pay_amount());
        }
        if (StockConstants.PAY_TYPE_FOR_SALE.equals(detailExt.getType())) {
            JxcSaleOrderExt orderExt = jxcSaleOrderMapper.selectBySid(detailExt.getOrder_sid());
            super.checkEmpty(orderExt, "销售单不存在");
            double unReceiveAmount = DoubleUtil.sub(orderExt.getShould_receive_amount(), totalAmount);
            if (unReceiveAmount < 0) {
                throw new HlpException("已收金额不能大于应收金额");
            }
            orderExt.setReceived_amount(BigDecimal.valueOf(totalAmount));
            orderExt.setUn_receive_amount(BigDecimal.valueOf(unReceiveAmount));
            super.autoInjectBaseData(orderExt, opUser, this.TYPE_UPDATE);
            jxcSaleOrderMapper.updateByPrimaryKeySelective(orderExt);
            detailExt.setRemain_amount(orderExt.getUn_receive_amount());
        }
        jxcOrderAmountDetailMapper.updateByPrimaryKeySelective(detailExt);
    }

    @Override
    public void saveJxcOrderAmountDetail4Batch(JxcOrderAmountDetailExt detailExt, SysUser opUser) throws Exception {
        super.checkEmptyList(detailExt.getOrder_list(), "参数：order_list 不能为空");
        if (detailExt.getOrder_list().size() == 1) {
            detailExt.setOrder_sid(detailExt.getOrder_list().get(0));
            this.saveJxcOrderAmountDetail(detailExt, opUser);
            return;
        }
        //根据订单列表获取各个订单已收付款的金额合计，amount的值是合计金额
        List<JxcOrderAmountDetailExt> totalList = jxcOrderAmountDetailMapper.sumValidByOrderList(detailExt.getOrder_list());
        if (StockConstants.PAY_TYPE_FOR_BUY.equals(detailExt.getType())) {
            this.batchSaveData4Buy(detailExt, totalList, opUser);
        } else if (StockConstants.PAY_TYPE_FOR_SALE.equals(detailExt.getType())) {
            this.batchSaveData4Sale(detailExt, totalList, opUser);
        } else {
            throw new HlpException("未处理的类型：" + detailExt.getType());
        }
    }

    /**
     * 批量生成采购单的付款和对账记录
     *
     * @param detailExt
     * @param totalList
     * @param opUser
     * @throws Exception
     */
    private void batchSaveData4Buy(JxcOrderAmountDetailExt detailExt, List<JxcOrderAmountDetailExt> totalList, SysUser opUser) throws Exception {
        JxcBuyOrderExt params = new JxcBuyOrderExt();
        params.setDr(0);
        params.setSid_list(detailExt.getOrder_list());
        List<JxcBuyOrderExt> list = jxcBuyOrderMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(list)) {
            return;
        }
        List<JxcBuyOrderExt> filterList = ListUtil.filter(list, t -> Constants.VALUE_YES != t.getState());
        if (!HlpUtils.isEmptyList(filterList)) {
            List<String> codeList = ListUtil.map(filterList, JxcBuyOrderExt::getCode);
            throw new HlpException("应付：" + StringUtils.join(codeList, "、") + " 已作废");
        }
        list = ListUtil.sorted(list, Comparator.comparing(JxcBuyOrderExt::getId));
        double amount = detailExt.getAmount().doubleValue();
        List<JxcFinanceAccountDetailExt> accountDetailExtList = new ArrayList<>();
        List<JxcOrderAmountDetailExt> insertList = new ArrayList<>();
        List<JxcBuyOrderExt> updateList = new ArrayList<>();
        for (JxcBuyOrderExt orderExt : list) {
            JxcOrderAmountDetailExt totalDetail = ListUtil.get(totalList, t -> t.getOrder_sid().equals(orderExt.getSid()));
            double totalAmount = 0D;
            if (totalDetail != null) {
                totalAmount = totalDetail.getAmount().doubleValue();
            }
            JxcOrderAmountDetailExt amountDetailExt = detailExt.copy();
            amountDetailExt.setOrder_sid(orderExt.getSid());
            double unPayAmount = DoubleUtil.sub(orderExt.getShould_pay_amount(), totalAmount);
            if (unPayAmount == 0) {
                continue;
            }
            if (unPayAmount >= amount) {
                //当某个订单的未收金额大于或等于收付款金额的余额时，处理后，不再继续处理其他订单
                unPayAmount = DoubleUtil.sub(unPayAmount, amount);
                amountDetailExt.setAmount(BigDecimal.valueOf(amount));
                orderExt.setUn_pay_amount(BigDecimal.valueOf(unPayAmount));
                double paidAmount = DoubleUtil.sub(totalAmount, amount);
                orderExt.setPaid_amount(BigDecimal.valueOf(paidAmount));
                amountDetailExt.setRemain_amount(orderExt.getUn_pay_amount());
                super.autoInjectBaseData(orderExt, opUser, this.TYPE_UPDATE);
                updateList.add(orderExt);
                super.autoInjectBaseData(amountDetailExt, opUser, this.TYPE_CREATE);
                insertList.add(amountDetailExt);
                // 采购对账

                JxcFinanceAccountDetailExt accountDetailExt = this.genBuyPayFinanceAccountDetailObj(orderExt, detailExt, BigDecimal.valueOf(amount));
                if (accountDetailExt != null) {
                    accountDetailExtList.add(accountDetailExt);
                }
                break;
            } else {
                //当某个订单的未收金额小于收付款金额的余额时，对当前订单进行处理后继续下一个订单的处理
                amount = DoubleUtil.sub(amount, unPayAmount);
                amountDetailExt.setAmount(BigDecimal.valueOf(unPayAmount));
                amountDetailExt.setRemain_amount(BigDecimal.ZERO);
                orderExt.setPaid_amount(orderExt.getShould_pay_amount());
                orderExt.setUn_pay_amount(BigDecimal.ZERO);
                super.autoInjectBaseData(orderExt, opUser, this.TYPE_UPDATE);
                updateList.add(orderExt);
                super.autoInjectBaseData(amountDetailExt, opUser, this.TYPE_CREATE);
                insertList.add(amountDetailExt);
                // 采购对账
                JxcFinanceAccountDetailExt accountDetailExt = this.genBuyPayFinanceAccountDetailObj(orderExt, detailExt, BigDecimal.valueOf(unPayAmount));
                if (accountDetailExt != null) {
                    accountDetailExtList.add(accountDetailExt);
                }
            }
        }
        if (!HlpUtils.isEmptyList(insertList)) {
            ThreadPoolTaskUtil.executeInList4Split(insertList, false, itemList -> jxcOrderAmountDetailMapper.insertList(itemList));
        }
        if (!HlpUtils.isEmptyList(updateList)) {
            ThreadPoolTaskUtil.executeInList4Split(updateList, false, itemList -> jxcBuyOrderMapper.updateList(itemList));
        }
        // 采购对账
        if (!HlpUtils.isEmptyList(accountDetailExtList)) {
            this.genAccountDetail(accountDetailExtList, opUser);
        }
    }

    /**
     * 批量处理销售订单的收款和对账记录
     *
     * @param detailExt
     * @param totalList
     * @param opUser
     * @throws Exception
     */
    private void batchSaveData4Sale(JxcOrderAmountDetailExt detailExt, List<JxcOrderAmountDetailExt> totalList, SysUser opUser) throws Exception {
        JxcSaleOrderExt params = new JxcSaleOrderExt();
        params.setDr(0);
        params.setSid_list(detailExt.getOrder_list());
        List<JxcSaleOrderExt> list = jxcSaleOrderMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(list)) {
            return;
        }
        List<JxcSaleOrderExt> filterList = ListUtil.filter(list, t -> Constants.VALUE_YES != t.getState());
        if (!HlpUtils.isEmptyList(filterList)) {
            List<String> codeList = ListUtil.map(filterList, JxcSaleOrderExt::getCode);
            throw new HlpException("应收：" + StringUtils.join(codeList, "、") + " 已作废");
        }
        list = ListUtil.sorted(list, Comparator.comparing(JxcSaleOrderExt::getId));
        double amount = detailExt.getAmount().doubleValue();
        List<JxcFinanceAccountDetailExt> accountDetailExtList = new ArrayList<>();
        List<JxcOrderAmountDetailExt> insertList = new ArrayList<>();
        List<JxcSaleOrderExt> updateList = new ArrayList<>();
        for (JxcSaleOrderExt orderExt : list) {
            JxcOrderAmountDetailExt totalDetail = ListUtil.get(totalList, t -> t.getOrder_sid().equals(orderExt.getSid()));
            double totalAmount = 0D;
            if (totalDetail != null) {
                totalAmount = totalDetail.getAmount().doubleValue();
            }
            JxcOrderAmountDetailExt amountDetailExt = detailExt.copy();
            amountDetailExt.setOrder_sid(orderExt.getSid());
            double unReceiveAmount = DoubleUtil.sub(orderExt.getShould_receive_amount(), totalAmount);
            if (unReceiveAmount == 0) {
                continue;
            }
            if (unReceiveAmount >= amount) {
                //当某个订单的未收金额大于或等于收付款金额的余额时，处理后，不再继续处理其他订单
                unReceiveAmount = DoubleUtil.sub(unReceiveAmount, amount);
                amountDetailExt.setAmount(BigDecimal.valueOf(amount));
                orderExt.setUn_receive_amount(BigDecimal.valueOf(unReceiveAmount));
                double paidAmount = DoubleUtil.sub(totalAmount, amount);
                orderExt.setReceived_amount(BigDecimal.valueOf(paidAmount));
                amountDetailExt.setRemain_amount(orderExt.getUn_receive_amount());
                orderExt.setGen_finance(1);
                super.autoInjectBaseData(orderExt, opUser, this.TYPE_UPDATE);
                updateList.add(orderExt);
                super.autoInjectBaseData(amountDetailExt, opUser, this.TYPE_CREATE);
                insertList.add(amountDetailExt);
                // 销售对账
                JxcFinanceAccountDetailExt accountDetailExt = this.genSalePayFinanceAccountDetailObj(orderExt, detailExt, BigDecimal.valueOf(amount));
                if (accountDetailExt != null) {
                    accountDetailExtList.add(accountDetailExt);
                }
                break;
            } else {
                //当某个订单的未收金额小于收付款金额的余额时，处理后，不再继续处理其他订单
                amount = DoubleUtil.sub(amount, unReceiveAmount);
                amountDetailExt.setAmount(BigDecimal.valueOf(unReceiveAmount));
                amountDetailExt.setRemain_amount(BigDecimal.ZERO);
                orderExt.setReceived_amount(orderExt.getShould_receive_amount());
                orderExt.setUn_receive_amount(BigDecimal.ZERO);
                orderExt.setGen_finance(1);
                super.autoInjectBaseData(orderExt, opUser, this.TYPE_UPDATE);
                updateList.add(orderExt);
                super.autoInjectBaseData(amountDetailExt, opUser, this.TYPE_CREATE);
                insertList.add(amountDetailExt);
                // 销售对账
                JxcFinanceAccountDetailExt accountDetailExt = this.genSalePayFinanceAccountDetailObj(orderExt, detailExt, BigDecimal.valueOf(unReceiveAmount));
                if (accountDetailExt != null) {
                    accountDetailExtList.add(accountDetailExt);
                }
            }
        }
        if (!HlpUtils.isEmptyList(insertList)) {
            ThreadPoolTaskUtil.executeInList4Split(insertList, false, itemList -> jxcOrderAmountDetailMapper.insertList(itemList));
        }
        if (!HlpUtils.isEmptyList(updateList)) {
            ThreadPoolTaskUtil.executeInList4Split(updateList, false, itemList -> jxcSaleOrderMapper.updateList(itemList));
        }
        // 销售对账
        if (!HlpUtils.isEmptyList(accountDetailExtList)) {
            this.genAccountDetail(accountDetailExtList, opUser);
        }
    }

    @Override
    public List<JxcOrderAmountDetailExt> findJxcOrderAmountDetails(Map<String, Object> params, PageBean page) throws Exception {
        return jxcOrderAmountDetailMapper.selectByPage(params, page);
    }

    @Override
    public List<JxcOrderAmountDetailExt> findJxcOrderAmountDetails(Map<String, Object> params) throws Exception {
        return jxcOrderAmountDetailMapper.selectByParams(params);
    }

    /**
     * 生成对账
     *
     * @param accountDetailExtList
     */
    private void genAccountDetail(List<JxcFinanceAccountDetailExt> accountDetailExtList, SysUser opUser) throws Exception {
        if (!HlpUtils.isEmptyList(accountDetailExtList)) {
            for (JxcFinanceAccountDetailExt detailExt : accountDetailExtList) {
                jxcFinanceAccountDetailService.saveJxcFinanceAccountDetail(detailExt, opUser);
            }
        }
    }

}
